package dk.iha;

import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothSocket;
import android.os.Handler;
import android.os.Message;
import android.util.Log;

public class BlackBoxBTSensor implements ISensor {

	//data from device: S,AA,BB,CC,DD,E
	//AA = afstand højre
	//BB = lyd tryk
	//CC = temperatur
	//DD = afstand venstre
	class BlackBoxData{
		int distanceRight;
		int soundPressure;//dB
		int temperature;//For Phidget sensor  - Temperature in Celcius = SensorValue*0.2222 - 61.111
		int distanceLeft;
	}

    private List<Byte> tmpBuffer = new ArrayList<Byte>();
    private List<BlackBoxData> data = null; 
    private BluetoothSocket mmSocket;
	private BluetoothDevice BTdev = null;
	private boolean running = false;
	ConnectBTDeviceThread connectThread = null;
	
	/**
	 * Parses the data in tmpBuffer.  
	 *  and sends complete packets (sequences starting with a 'S' and ending with an 'E')
	 *  to the function 'handlePacket'
	 */
	private void parsedata(){
		ArrayList<Byte> localBuf=null;
		//last position of 'E' byte
		int lastEnd=0;
		
		for(int iter=0 ; iter<tmpBuffer.size(); iter++){
			final Byte b=tmpBuffer.get(iter);
			if(b=='S'){
				localBuf = new ArrayList<Byte>();
				localBuf.add(b);
			}
			else if(b=='E'){
				if(localBuf != null){
					localBuf.add(b);
					handlePacket(localBuf);
				}
				lastEnd = iter;
			}
			else{
				if(localBuf != null)
					localBuf.add(b);
			}
		}
		//delete tmpBuffer array up to and with lastEnd
		List<Byte> tmpTmp = new ArrayList<Byte>(tmpBuffer.subList(lastEnd, tmpBuffer.size()));
		tmpBuffer = tmpTmp;
	}

	/**
	 * interprets the data in 'packet' as a BlackBoxData and appends to data
	 * @param packet  contains one packet. first byte must be 'S' last must be 'E'
	 */
	private void handlePacket(List<Byte> packet){
		if(packet.size() == 0)
			return;
		if(packet.get(packet.size()-1) != 'E' && packet.get(0) != 'S')
			return;
		
		String str="";
		for(Byte b : packet){
			str += (char)(b.byteValue());
		}
		Log.w("tag", "handlePacket:"+str);
		
		packet.remove(0);
		packet.remove(packet.size()-1);
		
		List<Integer> split = splitList(packet, ',');
		if(split!=null && split.size()==4)
		{
			BlackBoxData d = new BlackBoxData();
			d.distanceRight = split.get(0);
			d.soundPressure = split.get(1);
			d.temperature = split.get(2);
			d.distanceLeft = split.get(3);
			data.add(d);
		}
	}
	
	private List<Integer> splitList(List<Byte> lst, Character splitChar){
		StringBuilder bld= new StringBuilder();
		for(Byte b : lst)
			bld.append( (char)(b.byteValue()) );
		
		String[] strLst = bld.toString().split(",");
		
		List<Integer> retVal = new ArrayList<Integer>(); 
		for(String str : strLst){
			if(str.length()>0){
				int number;
				try{
					number = Integer.decode(str);
				}
				catch(NumberFormatException e){
					//the format is NOT correct of the packet
					return null;
				}
				retVal.add(number);
			}
		}
		return retVal;
	}
	
	/**
	 * Adds data to the end of the tmpBuffer
	 * @param buffer
	 */
	private void addData(List<Byte> buffer){
		tmpBuffer.addAll(buffer);
		parsedata();
	}
	

    private Handler connectTimerHandler = new Handler();
    private Runnable connectTimerHandlerTimeout = new Runnable() {
    	public void run() {
	       	if(isRunning()){
	   			connect();
	       	}
    	}
    };

    
    
    int connectionAttempt=0;
    int fail=0;
    /**
     *  ConnectBTDeviceHandler.handleMessage is called from the connectthread 
     *  with the connection result
     *  msg.what == 1 => conenction success
     *  msg.what == -1 => conenction failed
     */
	Handler ConnectBTDeviceHandler = new Handler(){        
        public void handleMessage(Message msg) {
        	//Thread has finished connecting
        	Log.w("WW","Main Thread:"+Thread.currentThread().getId());

        	//connection failed
        	if(msg.what == -1){
        		//retry connection to the device in 5000ms
            	Log.e("WW","ConnectBTDeviceHandler CONN FAILED - connection ID:"+ String.valueOf(connectionAttempt));
        		fail++;
            	connectTimerHandler.postDelayed(connectTimerHandlerTimeout, 5000);
        		return;
        	}
        	
        	//initialise local socket
        	mmSocket = connectThread.getSocket();
        	if(mmSocket != null && mmSocket.isConnected())
        	{
            	Log.w("WW","ConnectBTDeviceHandler CONN SUCCESS - connection ID:"+ String.valueOf(connectionAttempt) + " fail count:"+ String.valueOf(fail) );
        		//initialise read data timer
        		ReadDataTimerHandlerTimeout.run();
        	}
        };
    };

	
		
	//Time between reads on the Bluetooth socket
    final int readTimerTime=1000;//milli seconds
    //size of the max amount of data readable at one time
    final int bufferSize=1000;
    private byte buffer[] = new byte[bufferSize];
    
    
	Handler ReadDataTimerHandler = new Handler();
    private Runnable ReadDataTimerHandlerTimeout = new Runnable() {
    	public void run() {
    		//do the actual data collection to a data structure
    		try {
        		//Set up the runnable to run in  ACCELEROMETER_SAMPLE_PERIOD  (ms) again
    			ReadDataTimerHandler.postDelayed(ReadDataTimerHandlerTimeout, readTimerTime);
    			if(mmSocket != null && mmSocket.isConnected()){
    				InputStream inStream = mmSocket.getInputStream();
    				int count=0;
    				if(inStream.available() > 0) //make sure read does not block
    					count = inStream.read(buffer);

    				List<Byte> lst = new ArrayList<Byte>(count);
    				for(int i=0; i<count ; i++)
    					lst.add(buffer[i]);
					addData(lst);
    			}				
			} catch (IOException e) {
				e.printStackTrace();
			}
    	}
    };

	
	
	
	
	public BlackBoxBTSensor(BluetoothDevice dev){
		SharedData.getInstance().addDebugDataLog_t("BlackBoxBTSensor btdevice:"+(dev == null ? "null":dev.getAddress()));
		BTdev = dev;
	}
	
	public void start() {
		Log.d("WW", "BlackBoxBTSensor.start");

		//initialise data structure
		data = new ArrayList<BlackBoxData>();
		
		//update state flag
		running=true;
		
		// Connect to the device
		connectionAttempt++;
		connect();
	}


	/*
	 * Starts a thread that will try to connect to the remote Bluettoth device
	 */
	private void connect(){
		SharedData.getInstance().addDebugDataLog_t("BlackBoxBTSensor.connect BTdev:"+(BTdev==null ? "null" : BTdev.getAddress()));
		connectThread = new ConnectBTDeviceThread(BTdev, ConnectBTDeviceHandler);
		connectThread.start();
	}
	
	public List<BlackBoxData> getData(){
		Log.d("WW", "BlackBoxBTSensor.getData()");
		return data;
	}

	
	public void stop() {
		Log.d("WW", "BlackBoxBTSensor.stop()");

		//update state flag
		running=false;
		
		//cancel read timer
		ReadDataTimerHandler.removeCallbacks(ReadDataTimerHandlerTimeout);
		
		//cancel connect timer
		connectTimerHandler.removeCallbacks(connectTimerHandlerTimeout);
		
		//Shut down connection to the remote Bluetooth device
		try {
			if(mmSocket != null)
				mmSocket.close();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	public boolean isRunning() {
		Log.d("WW", "BlackBoxBTSensor.isRunning()");
		return running;
	}

}
